package org.jeecg.modules.third.openapi;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.DictModel;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.system.mapper.SysDictMapper;
import org.jeecg.modules.wlhy.hyconfig.entity.HyConfig;
import org.jeecg.modules.wlhy.hyvehicle.service.IHyVehicleService;
import org.jeecg.modules.wlhy.utils.HyConfigUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;

@Service
@Slf4j
public class ZWLOpenApiService {

    @Value(value = "${zwl.baseUrl:}")
    private String baseUrl;

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private SysDictMapper sysDictMapper;



    private final String ZWL_API_TOKEN_KEY = "ZWL_Api_Token";

    private final Integer ZWL_API_TOKEN_KEY_EXPIRE = 60 * 60 * 24;

    private static final String HMAC_SHA1 = "HmacSHA1";
    public static final char[] DIGITAL = "0123456789ABCDEF".toCharArray();


    //登录
    public String getLoginToken() {
        String token = null;
        try {
            HyConfig systemConfig = HyConfigUtils.getConfig();
            if (systemConfig == null || !systemConfig.getZwlIsUse()) {
                throw new JeecgBootException("中物联轨迹查询服务未开启,请联系管理员");
            }
            Map<String, String> params = new HashMap<String, String>();
            params.put("user", systemConfig.getZwlUser());
            params.put("pwd", systemConfig.getZwlPwd());
            params.put("srt", systemConfig.getZwlSrt());
            params.put("cid", systemConfig.getZwlCid());


            String url = baseUrl + "/api/getdata/comlogin";
            log.info("中物联请求Token参数 -> {} {}", url, JSONUtil.toJsonStr(params));
            // 1、处理参数
            processParam(params);
            // 2、将 map 参数拼接成 string 格式
            String reqBody = convertMapToString(params);
            System.out.printf("Request - url: %s, reqBody: %s\n", url, reqBody);
            if (!false) {
                // 信任证书
                trustAllCerts();
                // 信任域名
                trustAllHosts();
            }

            String res = cn.hutool.http.HttpUtil.post(url, JSONUtil.toJsonStr(reqBody));
            JSONObject jsonObject = JSONObject.parseObject(res);
            log.info("请求Token回执 <- {}" + res);
            int status = jsonObject.getIntValue("status");
            if (status != 1001) {
                throw new JeecgBootException("中物联联交互失败:" + jsonObject.getString("result"));
            }
            token = jsonObject.getString("result");
            if (StrUtil.isEmpty(token)) {
                throw new JeecgBootException("中交慧联获取令牌异常");
            }

            redisUtil.set(ZWL_API_TOKEN_KEY, token, ZWL_API_TOKEN_KEY_EXPIRE);


        } catch (Exception e) {
            log.debug(e.getMessage());
        }
        return token;

    }

    /**
     * * 信任所有域名
     */


    private static void trustAllHosts() {
        HostnameVerifier trustAllHosts = (hostname, session) -> true;
        HttpsURLConnection.setDefaultHostnameVerifier(trustAllHosts);

    }

    /**
     * 处理参数：①移除 srt，②计算签名，③增加 sign；
     *
     * @param param 原始参数
     */
    private static void processParam(Map<String, String> param) throws Exception {
        if (!param.containsKey("srt")) {
            throw new NullPointerException();
        }
        String srt = param.remove("srt");
        List<String> paramValueList = new ArrayList<>();
        for (Map.Entry<String, String> entry : param.entrySet()) {
            paramValueList.add(entry.getKey() + entry.getValue());
        }
        Collections.sort(paramValueList);
        String[] data = new String[paramValueList.size()];
        paramValueList.toArray(data);
        byte[] signature = hmacSha1(data, srt.getBytes(StandardCharsets.UTF_8));
        String sign = encodeHexStr(signature);
        param.put("sign", sign);
        param.put("v", "7.0");
    }

    /**
     * 将参数转换为字符串
     *
     * @param param 请求参数
     */


    private static String convertMapToString(Map<String, String> param) {
        StringBuilder sb = new StringBuilder();
        if (param != null && !param.isEmpty()) {
            for (Map.Entry<String, String> entry : param.entrySet()) {
                sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");

            }
            sb.deleteCharAt(sb.length() - 1);

        }
        return sb.toString();

    }

    private static void trustAllCerts() throws Exception {

        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        }};

    }

    /**
     * 178. * HmacSha1 定制算法
     * 179. *
     * 180. * @param strings 内容
     * 181. * @param key key
     * 182. * @return 签名
     * 183.
     */


    private static byte[] hmacSha1(String[] strings, byte[] key) throws Exception

    {
        SecretKeySpec signingKey = new SecretKeySpec(key, HMAC_SHA1);
        Mac mac = Mac.getInstance(HMAC_SHA1);
        mac.init(signingKey);
        for (String data : strings) {
            mac.update(data.getBytes(StandardCharsets.UTF_8));

        }
        return mac.doFinal();

    }

    /**
     * * 字节转为 Hex 字符串
     * *
     * * @param bytes 字节数组
     * <p>
     * <p>
     * * @return Hex 字符串
     */


    private static String encodeHexStr(final byte[] bytes) {
        if (bytes == null) {
            return null;

        }
        char[] result = new char[bytes.length * 2];
        for (int i = 0; i < bytes.length; i++) {
            result[i * 2] = DIGITAL[(bytes[i] & 0xf0) >> 4];
            result[i * 2 + 1] = DIGITAL[bytes[i] & 0x0f];

        }
        return new String(result);
    }

    //获取历史轨迹
    public String queryZwlTruckHisTrack(Map<String, String> reqMap) {

        try {

            String url = baseUrl + "/api/getdata/vHisTrackVinCom";

            log.info("中物联请求历史轨迹参数 -> {} {}", url, JSONUtil.toJsonStr(reqMap));
            // 1、处理参数
            processParam(reqMap);
            // 2、将 map 参数拼接成 string 格式
            String reqBody = convertMapToString(reqMap);
            System.out.printf("Request - url: %s, reqBody: %s\n", url, reqBody);
            if (!false) {
                // 信任证书
                trustAllCerts();
                // 信任域名
                trustAllHosts();
            }
            String res = cn.hutool.http.HttpUtil.post(url, JSONUtil.toJsonStr(reqBody));
            log.info("中物联返回参数回执 <- {}" + res);
            JSONObject jsonObject = JSONObject.parseObject(res);
            int status = jsonObject.getIntValue("status");
            //把返回的状态码与字典值中的状态进行比对，如果一致则返回字段值的内容
            List<DictModel> zwl_status = sysDictMapper.queryDictItemsByCode("ZWL_status");
            for (DictModel model : zwl_status) {
                if (String.valueOf(status).equals("1016")) {
                    redisUtil.del(ZWL_API_TOKEN_KEY);
                }
                if (String.valueOf(status).equals(model.getValue())&&!String.valueOf(status).equals("1001")){
                    throw new JeecgBootException(model.getText());

                }
            }
            return res;
        } catch (Exception e) {
            log.info("中物联车辆轨迹数据获取异常 {}", e.getMessage());
            e.printStackTrace();
            throw new JeecgBootException(e.getMessage());
        }

    }


    public String checkVehicleExist(Map<String, String> reqMap) {
        try {

            String url = baseUrl + "/api/GetData/checkVehicleExistV2";

            log.info("中物联获取车辆入网确认请求参数 -> {} {}", url, JSONUtil.toJsonStr(reqMap));
            // 1、处理参数
            processParam(reqMap);
            // 2、将 map 参数拼接成 string 格式
            String reqBody = convertMapToString(reqMap);
            System.out.printf("Request - url: %s, reqBody: %s\n", url, reqBody);
            if (!false) {
                // 信任证书
                trustAllCerts();
                // 信任域名
                trustAllHosts();
            }
            String res = cn.hutool.http.HttpUtil.post(url, JSONUtil.toJsonStr(reqBody));
            log.info("中物联车辆入网确认返回参数回执 <- {}" + res);
            JSONObject jsonObject = JSONObject.parseObject(res);
            int status = jsonObject.getIntValue("status");
            //把返回的状态码与字典值中的状态进行比对，如果一致则返回字段值的内容
            List<DictModel> zwl_status = sysDictMapper.queryDictItemsByCode("ZWL_status");
            for (DictModel model : zwl_status) {
                if (String.valueOf(status).equals("1016")) {
                    redisUtil.del(ZWL_API_TOKEN_KEY);
                }
                if (String.valueOf(status).equals(model.getValue())&&!String.valueOf(status).equals("1001")){
                    throw new JeecgBootException(model.getText());

                }
            }
            return res;
        } catch (Exception e) {
            log.info("中物联车辆入网确认数据获取异常 {}", e.getMessage());
            e.printStackTrace();
            throw new JeecgBootException(e.getMessage());
        }

    }
}
